package edu.hawaii.duedates;

import org.junit.Test;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;

import java.util.Collections;
import java.util.List;
import java.util.ArrayList;
import edu.hawaii.duedates.lender.BorrowedItem;
import edu.hawaii.duedates.lender.Lender;
import edu.hawaii.duedates.lender.HawaiiStatePublicLibrary;
import edu.hawaii.duedates.lender.UhManoaLibrary;
import edu.hawaii.duedates.lender.LogInException;

/**
 * Test class for DueDates class. 
 * Requires arguments of a valid uhm id and last name, valid hsl id and password, a valid
 * email address, and valid stmp server. 
 * 
 * @author Daniel Tian
 * @author Aric West
 *
 */
public class TestDueDates {
  private final DueDates dueDates;
  private final String[] args = {};
  
  /**
   * Constructor. Creates a DueDates object and creates the two library systems it supports.
   */
  public TestDueDates() {
    this.dueDates = new DueDates(args);
    this.dueDates.createUhManoaLibrary(System.getProperty("uhmid"), System.getProperty("uhmpass"));
    this.dueDates.createHawaiiStatePublicLibrary(System.getProperty("hslid"),
                                                 System.getProperty("hslpass"));
  }
  
  /**
   * Test creating a UH Manoa Library object.
   */
  @Test
  public void testCreateUhManoaLibrary() {
    Lender uhm = new UhManoaLibrary();
    
    assertEquals("UH Manoa created successfully", uhm, this.dueDates.getLenderList().get(0)); 
  }
  
  /**
   * Test creating a Hawaii State Library object.
   */
  @Test
  public void testCreateHawaiiStatePublicLibrary() {
    Lender hsl = new HawaiiStatePublicLibrary();
    assertEquals("Hawaii State created successfully", hsl, this.dueDates.getLenderList().get(1));
  }
  
  /**
   * Test getting borrowed items, sorting by lender name, and sorting by due date.
   * 
   * @throws Exception Throws on all non-runtime exceptions.
   */
  @Test
  public void testGettingBorrowedItems() throws Exception {
    // test normal login and query lenders
    this.dueDates.logInAllLenders();
    this.dueDates.queryAllLenders();
    
    for (Lender lender : this.dueDates.getLenderList()) {
      assertFalse("Item list not empty", lender.getItemList().isEmpty());
    }
    
    // test sort by lender name
    this.dueDates.sortByLenderName();
    assertTrue("Hawaii State is first",
               this.dueDates.getLenderList().get(0) instanceof HawaiiStatePublicLibrary);
    assertTrue("UH Manoa is second",
               this.dueDates.getLenderList().get(1) instanceof UhManoaLibrary);
  
    // test sort by due date
    List<BorrowedItem> hslList = new ArrayList<BorrowedItem>();
    List<BorrowedItem> uhmList = new ArrayList<BorrowedItem>();
    
    for (BorrowedItem item : this.dueDates.getLenderList().get(0).getItemList()) {
      hslList.add(item);
    }
    
    for (BorrowedItem item : this.dueDates.getLenderList().get(1).getItemList()) {
      uhmList.add(item);
    }
    
    Collections.sort(hslList);
    Collections.sort(uhmList);
    dueDates.sortByDueDate();
    
    assertEquals("Hawaii State item list is sorted", hslList,
                 this.dueDates.getLenderList().get(0).getItemList());
    assertEquals("UH Manoa item list is sorted", uhmList,
                 this.dueDates.getLenderList().get(1).getItemList());
  }
  
  /**
   * Test bad login info will throw LogInException when trying to log in all lenders.
   * 
   * @throws Exception Thrown when logging in fails.
   */
  @Test(expected = LogInException.class)
  public void testBadLogIn() throws Exception {
    DueDates dueDates = new DueDates(args);
    
    dueDates.createHawaiiStatePublicLibrary(null, null);
    dueDates.logInAllLenders();
  }
  
  /**
   * Test bad login info will throw LogInException when trying to query all lenders.
   * 
   * @throws Exception Thrown when logging in fails.
   */
  @Test(expected = LogInException.class)
  public void testQueryLendersWithBadLogin() throws Exception {
    DueDates dueDates = new DueDates(args);
    
    dueDates.createHawaiiStatePublicLibrary(null, null);
    dueDates.queryAllLenders();
  }
  
  /**
   * Test email functionality.
   * 
   */
  @Test
  public void testEmail() {
    String[] args = {"-uhm", System.getProperty("uhmid"), System.getProperty("uhmpass"), "-email",
        System.getProperty("email"), System.getProperty("smtpServer")};
    DueDates dueDates = new DueDates(args);
    dueDates.setOutput(dueDates.getConsole().printBorrowedItems());
    System.out.println(dueDates.getOutput()); 
    dueDates.emailResults(dueDates.getConsole().getEmailAddress(),
        dueDates.getConsole().getSmtpServer());
    assertFalse("This is a lie", dueDates.getConsole().isErrorOccurred());
  }
  
  /**
   * Test -wakeup being parsed.
   * 
   */
  @Test
  public void testWakeup() {
    String[] args = {"-uhm", System.getProperty("uhmid"), System.getProperty("uhmpass"), "-console",
        "-wakeup", "1", "-within", "5"};
    DueDates dueDates = new DueDates(args);
    assertEquals("wake up value parsed", dueDates.getWakeupValue().intValue(), 1);
    if (dueDates.getWakeupValue() > 0) {
      dueDates.run();
    }
  }
}
